home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 21
/
Cream of the Crop 21 (Terry Blount) (October 1996).iso
/
doom
/
quake.zip
/
QUDPROXY.ZIP
/
QUDPROXY.GZ
/
QUDPROXY
/
qudproxy.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-10
|
7KB
|
264 lines
/* Quake UDP proxy
Original ipx->udp proxy by tz@execpc.com
Adapted for udp->udp, other changes by jason@cygnus.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
compile with "gcc -O2 -o qudproxy qudproxy.c"
version 1.0
todo: translate broadcasts, server list
Note: This program properly handles proxying for multiple clients, but
as of Quake 0.92 the quake server only allows one client from each IP
address, so only one player can use the proxy at a time; if another
player connects to the proxy, the remote server will disconnect the
first player. I've complained about this to id.
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
extern char *optarg;
extern int optind;
#define VERSION "1.0"
#define MAX 4096
unsigned char msg[MAX];
char *name;
void usage ()
{
fprintf (stderr, "usage: %s [-l localport] [-r remoteport]", name);
fprintf (stderr, " [-d[d]] [-h] server\n");
}
int main (int argc, char *argv[])
{
int sfd, cfd, c2fd, n, ucl, i, pid, opt;
fd_set fds;
struct sockaddr_in cremote_addr, clocal_addr;
struct sockaddr_in sremote_addr, slocal_addr;
struct hostent *host;
struct timeval tv, *tvp;
int localport = 26000, remoteport = 26000, debug = 0;
name = argv[0];
while (opt = getopt (argc, argv, "l:r:dhv"), opt != -1)
{
switch (opt)
{
case 'l':
localport = atoi (optarg);
break;
case 'r':
remoteport = atoi (optarg);
break;
case 'd':
++debug;
break;
case 'v':
fprintf (stderr, "qudproxy version %s", VERSION);
return 0;
default:
usage ();
return opt != 'h';
}
}
if (optind != argc - 1)
{
usage ();
return 1;
}
ucl = sizeof (struct sockaddr_in);
bzero (&sremote_addr, ucl);
sremote_addr.sin_family = AF_INET;
sremote_addr.sin_port = htons (remoteport);
n = inet_addr (argv[optind]);
if (n != -1)
memcpy (&sremote_addr.sin_addr, &n, sizeof(n));
else
{
host = gethostbyname (argv[optind]);
if (host == NULL)
return (-1);
memcpy (&sremote_addr.sin_addr, host->h_addr, host->h_length);
}
bzero (&clocal_addr, ucl);
clocal_addr.sin_family = AF_INET;
clocal_addr.sin_port = htons (localport);
/* Surely there's a better way to determine our IP address. */
gethostname (msg, MAX);
host = gethostbyname (msg);
memcpy (&clocal_addr.sin_addr, host->h_addr, host->h_length);
bzero (&slocal_addr, ucl);
slocal_addr.sin_family = AF_INET;
slocal_addr.sin_addr.s_addr = htonl(INADDR_ANY);
cfd = socket (AF_INET, SOCK_DGRAM, 0);
bind (cfd, (struct sockaddr *) &clocal_addr, ucl);
sfd = socket (AF_INET, SOCK_DGRAM, 0);
bind (sfd, (struct sockaddr *) &slocal_addr, ucl);
tvp = NULL;
for (;;)
{
int i;
/* this is to exit the spawned processes */
if (tvp != NULL)
{
tv.tv_sec = 15;
tv.tv_usec = 0;
}
FD_ZERO (&fds);
FD_SET (sfd, &fds);
FD_SET (cfd, &fds);
if (0 >= select (1 + (cfd > sfd ? cfd : sfd), &fds, NULL, NULL, tvp))
return 0;
/* this should be the 12 byte connect request broadcast */
if (FD_ISSET (cfd, &fds))
{
n = recvfrom (cfd, msg, MAX, 0,
(struct sockaddr *) &cremote_addr, &ucl);
if (n == -1)
{
perror ("qudproxy");
return 1;
}
if (debug > 1)
{
fprintf (stderr, "client@%d: ", ntohs (cremote_addr.sin_port));
for (i = 0; i < n; ++i)
fprintf (stderr, "%x ", msg[i]);
fflush (stderr);
write (2, "(", 1);
write (2, msg, n);
write (2, ")\n", 2);
}
sendto (sfd, msg, n, 0, (struct sockaddr *) &sremote_addr, ucl);
}
if (FD_ISSET (sfd, &fds))
{
/* SunOS 4.1.3_U1 requires that we pass in &ucl. Odd. */
n = recvfrom (sfd, msg, MAX, 0, NULL, &ucl);
if (n == -1)
{
perror ("qudproxy");
return 1;
}
if (debug > 1)
{
fprintf (stderr, "server@%d: ", ntohs (sremote_addr.sin_port));
for (i = 0; i < n; ++i)
fprintf (stderr, "%x ", msg[i]);
fflush (stderr);
write (2, "(", 1);
write (2, msg, n);
write (2, ")\n", 2);
}
/* this might be the connect response */
if (tvp == NULL && msg[0] == 0x80 && msg[1] == 00
&& msg[4] == 0x81)
{
#if 1
/* FORK HERE */
pid = fork ();
if (!pid)
{
/* spawn again */
if (pid = fork (), pid)
{
if (debug)
fprintf (stderr,
"Spawning Quake Proxy Handler Pid %d\n",
pid);
return 0;
/* if parent, exit (so init gets grandkid) */
}
}
else
{
/* wait for kid to exit and continue */
waitpid (pid, NULL, 0);
/* create new udp socket for next connections */
close (sfd);
sfd = socket (AF_INET, SOCK_DGRAM, 0);
bind (sfd, (struct sockaddr *) &slocal_addr, ucl);
continue;
}
/* we are in grandkid */
#endif
sremote_addr.sin_port = htons (msg[5] + (msg[6] << 8));
clocal_addr.sin_port = 0;
c2fd = socket (AF_INET, SOCK_DGRAM, 0);
bind (c2fd, (struct sockaddr *) &clocal_addr, ucl);
getsockname (c2fd, (struct sockaddr *) &clocal_addr, &ucl);
msg[5] = ntohs (clocal_addr.sin_port) & 0xff;
msg[6] = ntohs (clocal_addr.sin_port) >> 8;
if (debug)
{
fprintf (stderr, "Quake UDP Proxy to %s:%d",
inet_ntoa (sremote_addr.sin_addr),
ntohs (sremote_addr.sin_port));
#if 0
/* We haven't asked for this information with
getsockname. */
fprintf (stderr, " from %s:%d",
inet_ntoa (slocal_addr.sin_addr),
ntohs (slocal_addr.sin_port));
#endif
fprintf (stderr, " for %s:%d",
inet_ntoa (cremote_addr.sin_addr),
ntohs (cremote_addr.sin_port));
fprintf (stderr, " at %s:%d\n",
inet_ntoa (clocal_addr.sin_addr),
msg[5] + (msg[6] << 8));
fflush (stderr);
}
tvp = &tv;
sendto (cfd, msg, n, 0, (struct sockaddr *) &cremote_addr, ucl);
close (cfd);
cfd = c2fd;
}
else
sendto (cfd, msg, n, 0, (struct sockaddr *) &cremote_addr, ucl);
}
}
}